package edu.colorado.core;

import java.io.Serializable;

public class Board implements Serializable
{
    private static final long serialVersionUID = -7882217463242940935L;
    
    private static enum Path { None, R, D, DR, DL }
    
    private int[][] boardState;
    private Integer numOfPieces;
    private Integer height, width;

    Board()
    {
        setHeight(6);
        setWidth(7);
        setBoardState(new int[getWidth()][getHeight()]);
        for(Integer i=0; i<getWidth(); i++)
        {
            for(Integer j=0; j<getHeight(); j++)
            {
                getBoardState()[i][j] = 2; // empty cell
            }

        }
        numOfPieces = 0;
    }

    Board(Board otherBoard)
    {
        setHeight(6);
        setWidth(7);
        setBoardState(new int[getWidth()][getHeight()]);
        for(Integer i=0; i<getWidth(); i++)
        {
            for(Integer j=0; j<getHeight(); j++)
            {
                getBoardState()[i][j] = otherBoard.getBoardState()[i][j];
            }

        }
        numOfPieces = otherBoard.getNumOfPieces();
    }

    Integer getNumOfPieces()
    {
        return numOfPieces;
    }

    void setNumOfPieces(Integer numOfPieces)
    {
        this.numOfPieces = numOfPieces;
    }



    void putPiece(Integer x, Integer y, Integer type)
    {
        getBoardState()[x][y] = type;
        numOfPieces ++;
    }

    public Integer getPiece(int x, int y)
    {
        return getBoardState()[x][y];
    }

    public Integer getRows()
    {
        return getHeight();
    }

    public Integer getCols()
    {
        return getWidth();
    }
    
    public int[][] getFour(int disc) {
        int[][] path = new int[2][4];
        
        for (int r = getHeight() - 1; r >= 0; r--) {
            for (int c = 0; c < getWidth(); c++) {
                switch (hasFour(disc, r, c)) {
                case D:
                    for (int i = 0; i < 4; i++) {
                        path[0][i] = r + i;
                        path[1][i] = c;
                    }
                    return path;
                case R:
                    for (int i = 0; i < 4; i++) {
                        path[0][i] = r;
                        path[1][i] = c + i;
                    }
                    return path;
                case DL:
                    for (int i = 0; i < 4; i++) {
                        path[0][i] = r + i;
                        path[1][i] = c - i;
                    }
                    return path;
                case DR:
                    for (int i = 0; i < 4; i++) {
                        path[0][i] = r + i;
                        path[1][i] = c + i;
                    }
                    return path;
                }
            }
        }
        
        return null;
    }
    
    private Path hasFour(int disc, int r, int c) {
        boolean right = true, down = true, dRight = true, dLeft = true;
        
        for (int i = 0; i < 4; i++) {
            if (c + i >= getWidth() || getPiece(c + i, r) != disc) {
                right = false;
            }
            if (r + i >= getHeight() || getPiece(c, r + i) != disc) {
                down = false;
            }
            if (r + i >= getHeight() || c + i >= getWidth() ||
                    getPiece(c + i, r + i) != disc) {
                dRight = false;
            }
            if (r + i >= getHeight() || c - i < 0 ||
                    getPiece(c - i, r + i) != disc) {
                dLeft = false;
            }
        }
        
        if (right) {
            return Path.R;
        } else if (down) {
            return Path.D;
        } else if (dRight) {
            return Path.DR;
        } else if (dLeft) {
            return Path.DL;
        } else {
            return Path.None;
        }
    }
    
    public boolean canDrop(int col) {
        for (int row = getHeight() - 1; row >= 0; row--) {
            if (getPiece(col, row) == Algorithm.NONEOFTHETWO) {
                return true;
            }
        }
        return false;
    }

    void display()
    {
        System.out.print("|");
        for(Integer i=0; i<getWidth()*2+1; i++)
        {
            System.out.print("-");
        }
        System.out.println("|");

        for(Integer i=0; i<getHeight(); i++)
        {
            System.out.print("| ");
            for(Integer j=0; j<getWidth(); j++)
            {
                if(getBoardState()[j][getHeight()-i-1] == 0)
                {
                    System.out.print("X ");
                }
                else if(getBoardState()[j][getHeight()-i-1] == 1)
                {
                    System.out.print("0 ");
                }
                else
                {
                    System.out.print(". ");
                }
            }
            System.out.println("|");
        }

        System.out.print("|");
        for(Integer i=0; i<getWidth()*2+1; i++)
        {
            System.out.print("-");
        }
        System.out.println("|");
        
        System.out.print(" ");
        for(Integer i=0; i<getWidth(); i++)
        {
            System.out.print(" " + (i+1));
        }
        System.out.println();

    }

    public Integer getWidth()
    {
        return width;
    }

    public void setWidth(Integer width)
    {
        this.width = width;
    }

    public Integer getHeight()
    {
        return height;
    }

    public void setHeight(Integer height)
    {
        this.height = height;
    }

    public int[][] getBoardState()
    {
        return boardState;
    }

    public void setBoardState(int[][] boardState)
    {
        this.boardState = boardState;
    }
}

